#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include<sys/types.h>
#include<sys/wait.h>
#include "log.hpp"
#include"Thread.hpp"
#include"ThreadPool.hpp"
#include "InetAddr.hpp"
using namespace ThreadModule;
static const int defaultsockfd = -1;
static const int backlog = 16;
using task_t = std::function<void()>; // 回调函数
enum
{
    USAGE_ERROR = 1,
    SOCKET_ERROR,
    BING_ERROR,
    LISTENERROR
};
class TcpServer;
class ThreadData
{
    public:
    ThreadData(int fd,InetAddr addr,TcpServer* s):_sockfd(fd),_clientaddr(addr),_self(s)
    {}
    public:
    int _sockfd;
    InetAddr _clientaddr;
    TcpServer* _self;
};
class TcpServer
{
public:
    TcpServer(uint16_t port) : _port(port), _listensock(defaultsockfd), _isruning(false)
    {}


    
    ~TcpServer()
    {}

    void Initserver()
    {
        // 创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LOG(FATAL, "create socket failed!!\n");
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG, "socked success, socked is %d\n", _listensock);
        // 2. bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = bind(_listensock, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind error\n");
            exit(BING_ERROR);
        }
        LOG(DEBUG, "bind success, socked is %d\n", _listensock);
        // 3. tcp是面向连接的，所以通信之前，必须要先建立连接，服务器是被连接的。
        // tcpserver启动，所以未来要一直等待客户的连接到来
        // 监听
        n = ::listen(_listensock, backlog);
        if (n < 0)
        {
            LOG(FATAL, "listen error\n");
            exit(LISTENERROR);
        }
        LOG(DEBUG, "listen success, socked is %d\n", _listensock);
    }

    void Service(int sockfd, InetAddr client)
    {
        LOG(DEBUG, "get a new link,info %s,%d,%d", client.Ip().c_str(), client.Port(),sockfd);
        std::string clientaddr = "[" + client.Ip() + ": " + std::to_string(client.Port()) + "]#";
        while (true)
        {
            char inbuffer[1024];
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                // 读取成功
                inbuffer[n] = 0;
                std::cout << clientaddr << inbuffer << std::endl;
                std::string echo_string  = "[server echo]#";
                echo_string +=inbuffer;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if(n == 0)
            {
                //client 退出 && 关闭连接了
                LOG(INFO,"%s quit\n",clientaddr.c_str());
                break;
            }
            else
            {
                LOG(ERROR,"read error\n",clientaddr.c_str());
                break;
            }
        }
        ::close(sockfd);//文件描述符泄漏
    }
    static void* Handlersock(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->_self->Service(td->_sockfd,td->_clientaddr);
        delete td;
        return nullptr;

    }
    void Loop()
    {
        _isruning = true;
        // 4. 不能直接接受数据，先获取连接
        while ((true))
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(_listensock, (struct sockaddr *)&peer, &len);
            if (sockfd < 0)//接受失败
            {
                LOG(WARNING, "accept error\n");
                continue;
            }
            // version 0
            //一次只能处理一个请求---不可能
            //Service(sockfd, InetAddr(peer));
            //version1  采用多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //child：关心sockfd，不关心listensock
            //     ::close(_listensock);//建议
            //     if(fork()> 0) exit(0);
            //     Service(sockfd,InetAddr(peer));//孙子进程---孤儿进程---系统进程
            //     exit(0);
            // }
            // //father；关心listensock,不关心sockfd
            // ::close(sockfd);
            // waitpid(id,nullptr,0);


            //version 3 
            //多线程
            // pthread_t t;
            // ThreadData *td = new ThreadData(sockfd,InetAddr(peer),this);
            // pthread_create(&t,nullptr,Handlersock,td);
            //采用线程池
            task_t t = std::bind(&TcpServer::Service,this,sockfd,InetAddr(peer));//将Service绑定this指针，并将sockfd 和 InetAddr给Service
            thread_pool<task_t>::GetInstance()->Enqueue(t);

        }
        _isruning = false;
    }

private:
    uint16_t _port;  // 端口号
    int _listensock; // 套接字文件描述符
    bool _isruning;
};